import StyleConfig from "./styleConfig";
import {isEmptyObject, Dom, http} from "../common/common";

class CaptchaConfig {
    constructor(args) {
        if (!args.bindEl) {
            throw new Error("[TAC] 必须配置 [bindEl]用于将验证码绑定到该元素上");
        }
        if (!args.requestCaptchaDataUrl) {
            throw new Error("[TAC] 必须配置 [requestCaptchaDataUrl]请求验证码接口");
        }
        if (!args.validCaptchaUrl) {
            throw new Error("[TAC] 必须配置 [validCaptchaUrl]验证验证码接口");
        }
        this.bindEl = args.bindEl;
        this.domBindEl = Dom(args.bindEl);
        this.requestCaptchaDataUrl = args.requestCaptchaDataUrl;
        this.validCaptchaUrl = args.validCaptchaUrl;
        if (args.validSuccess) {
            this.validSuccess = args.validSuccess;
        }
        if (args.validFail) {
            this.validFail = args.validFail;
        }
        if (args.requestHeaders) {
            this.requestHeaders = args.requestHeaders
        } else {
            this.requestHeaders = {}
        }
        if (args.getRequestBody) {
            this.getRequestBody = args.getRequestBody;
        }
        if (args.validRequestBody) {
            this.validRequestBody = args.validRequestBody;
        }
        if (args.btnCloseFun) {
            this.btnCloseFun = args.btnCloseFun;
        }
        if (args.btnRefreshFun) {
            this.btnRefreshFun = args.btnRefreshFun;
        }
        this.requestChain = [];
        this.addRequestChain(jm);
    }

    addRequestChain(fun) {
        this.requestChain.push(fun);
    }

    insertRequestChain(index, chain) {
        this.requestChain.splice(index, 0, chain);
    }

    removeRequestChain(index) {
        this.requestChain.splice(index, 1);
    }

    requestCaptchaData() {
        const requestParam = {}
        requestParam.headers = this.requestHeaders || {};
        requestParam.data = {};
        // 设置默认值
        requestParam.headers["Content-Type"] = "application/json;charset=UTF-8";
        requestParam.headers["x-referer"] = window.location.origin + window.location.pathname;
        requestParam.method = "POST";
        requestParam.url = this.requestCaptchaDataUrl;
        // 请求前装载参数
        this._preRequest("requestCaptchaData", requestParam);
        requestParam.data = this.getRequestBody ? {body: this.getRequestBody, captcha:requestParam.data} : requestParam.data;
        // 发送请求
        const request = this.doSendRequest(requestParam);
        // 返回结果
        return request.then(res => {
            // 装返回结果
            this._postRequest("requestCaptchaData", requestParam, res);
            // 返回结果
            return res;
        });
    }

    doSendRequest(requestParam) {
        // 如果content-type是json，那么data就是json字符串, 这里直接匹配所有header是否包含application/json
        if (requestParam.headers) {
            for (const key in requestParam.headers) {
                if (requestParam.headers[key].indexOf("application/json") > -1) {
                    if (typeof requestParam.data !== "string") {
                        requestParam.data = JSON.stringify(requestParam.data);
                    }
                    break;
                }
            }
        }
        return http(requestParam).then(res => {
            try {
                return JSON.parse(res);
            } catch (e) {
                return res;
            }
        })
    }

    _preRequest(type, requestParam, c, tac) {
        for (let i = 0; i < this.requestChain.length; i++) {
            const r = this.requestChain[i];
            if (r.preRequest) {
                if (!r.preRequest(type, requestParam, this, c, tac)) {
                    break;
                }
            }
        }

    }

    _postRequest(type, requestParam, res, c, tac) {
        for (let i = 0; i < this.requestChain.length; i++) {
            const r = this.requestChain[i];
            // 判断r是否存圩postRequest方法
            if (r.postRequest) {
                if (!r.postRequest(type, requestParam, res, this, c, tac)) {
                    break;
                }
            }
        }
    }

    validCaptcha(currentCaptchaId, data, c, tac) {
        const sendParam = {
            id: currentCaptchaId,
            data: data
        };
        let requestParam = {};
        requestParam.headers = this.requestHeaders || {};
        // 这里判断一下 是否有自定义的validRequestBody，如果有，则在请求体上封装一层
        requestParam.data = sendParam;
        requestParam.headers["Content-Type"] = "application/json;charset=UTF-8";
        requestParam.method = "POST";
        requestParam.url = this.validCaptchaUrl;

        this._preRequest("validCaptcha", requestParam, c, tac);
        // 封装自定义参数
        requestParam.data = this.validRequestBody ? {
            body: this.validRequestBody,
            captcha: requestParam.data
        } : requestParam.data;
        const request = this.doSendRequest(requestParam);
        return request.then(res => {
            this._postRequest("validCaptcha", requestParam, res, c, tac);
            return res;
        }).then(res => {
            if (res.code === 200) {
                const useTimes = (data.stopTime - data.startTime) / 1000;
                c.showTips(c.styleConfig.i18n.tips_success.replace("%s", useTimes), 1, () => this.validSuccess(res, c, tac));
            } else {
                let tipMsg = c.styleConfig.i18n.tips_error;
                if (res.code) {
                    if (res.code !== 4001) {
                        tipMsg = c.styleConfig.i18n.tips_4001;
                    }
                }
                c.showTips(tipMsg, 0, () => this.validFail(res, c, tac));
            }
        }).catch(e => {
            let tipMsg = c.styleConfig.i18n.tips_error;
            if (e.code && e.code !== 200) {
                if (res.code !== 4001) {
                    tipMsg = c.styleConfig.i18n.tips_4001;
                }
                c.showTips(tipMsg, 0, () => this.validFail(res, c, tac));
            }
        })
    }

    validSuccess(res, c, tac) {
        console.log("验证码校验成功， 请重写  [config.validSuccess] 方法， 用于自定义逻辑处理")
        window.currentCaptchaRes = res;
        tac.destroyWindow();
    }

    validFail(res, c, tac) {
        tac.reloadCaptcha();
    }
}

function wrapConfig(config) {
    if (config instanceof CaptchaConfig) {
        return config;
    }
    return new CaptchaConfig(config);
}

function wrapStyle(style) {
    // if (!style) {
    //     style = {}
    // }
    let margeStyle = {...StyleConfig, ...style};
    margeStyle.i18n = {...StyleConfig.i18n, ...style?.i18n};
    return margeStyle;

    // if (!style.btnUrl) {
    //     // 设置默认图片
    //     style.btnUrl = "";
    // }
    // if (!style.moveTrackMaskBgColor && !style.moveTrackMaskBorderColor) {
    //     style.moveTrackMaskBgColor = "#89d2ff";
    //     style.moveTrackMaskBorderColor = "#0298f8";
    // }
    // return style;
}


const jm = {
    preRequest(type, param, c, tac) {
        if (type !== "validCaptcha") {
            return true;
        }
        // 加密
        const requestData = param.data.data;
        const encData = [];
        encData.push(this.pretreatment(requestData.startTime, 7, true))
        encData.push(this.pretreatment(requestData.stopTime, 7, true))
        encData.push(this.pretreatment(requestData.bgImageWidth, 3, true))
        encData.push(this.pretreatment(requestData.bgImageHeight, 3, true))
        encData.push(this.pretreatment(requestData.templateImageWidth, 3, true))
        encData.push(this.pretreatment(requestData.templateImageHeight, 3, true))
        encData.push(this.pretreatment(requestData.left, 3, true))
        encData.push(this.pretreatment(requestData.top, 3, true))
        encData.push(this.pretreatment(requestData.trackList.length, 3, true))
        encData.push(this.encryptTrack(requestData.trackList))
        if (requestData.data) {
            encData.push(this.encodeStr(JSON.stringify(requestData.data)));
        }
        param.data.data = encData.join("");
        return true;
    },
    encodeStr(str) {
        const bytes = [];
        for (let i = 0; i < str.length; i++) {
            let c = str.charCodeAt(i);
            bytes.push(c);
        }
        return bytes.join(",");
    },
    encryptTrack(trackList) {
        const encTrackList = [];
        for (let i = 0; i < trackList.length; i++) {
            let track = trackList[i];
            let type = 0;
            switch (track.type) {
                case "down":
                    type = 0;
                    break;
                case "move":
                    type = 1;
                    break;
                case "up" :
                    type = 2;
                    break;
                case "click":
                    type = 3;
            }
            if (i === 0) {
                encTrackList.push(this.pretreatment(track.x, 3, false));
                encTrackList.push(this.pretreatment(track.y, 3, false));
                encTrackList.push(this.pretreatment(track.t, 4, true));
                encTrackList.push(type);
            } else {
                let preTrack = trackList[i - 1];
                encTrackList.push(this.pretreatment(track.x - preTrack.x, 3, false));
                encTrackList.push(this.pretreatment(track.y - preTrack.y, 3, false));
                encTrackList.push(this.pretreatment(track.t - preTrack.t, 4, true));
                encTrackList.push(type);
            }
        }
        return encTrackList.join("");
    },
    string10to64(data) {
        let dict = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~'['split'](''),
            count = dict.length,
            d = +data,
            e = [];
        do {
            let mod = d % count;
            d = (d - mod) / count;
            e['unshift'](dict[mod]);
        } while (d);
        return e['join']('');
    },
    prefixInteger(a, b) {
        return (Array(b)['join'](0x0) + a)['slice'](-b);
    },
    pretreatment(data, count, c) {
        const e = this.string10to64(Math['abs'](data));
        let f = '';
        if (!c) {
            f += data >= 0 ? '1' : '0';
        }
        f += this.prefixInteger(e, count);
        return f;
    }
}
export {CaptchaConfig, wrapConfig, wrapStyle}
